//
// Created by 抑~风 on 2022/11/20.
//

#include"regexp.h"
#include<iostream>
using namespace std;
namespace CWJ{

    unsigned int NfaNode::id{0};

    void NfaGraph::regexAST2nfaGraph(NfaGraph::ASTNodePtr root){
        auto res = this->regexAST2nfaGraphDfs(root);
        this->startState = res.first;
        this->endState = res.second;

    }

    NfaGraph::PNN NfaGraph::regexAST2nfaGraphDfs(NfaGraph::ASTNodePtr root){

        NfaGraph::NfaNodePtr startState = nullptr;
        NfaGraph::NfaNodePtr endState = nullptr;
        PNN vs ;
        switch (root->getType()) {
            case NodeType::OR:
                startState = make_shared<NfaNode>();
                endState = make_shared<NfaNode>(true);
                for(auto& one : root->getChilds()){
                    vs = this->regexAST2nfaGraphDfs(dynamic_pointer_cast<NfaGraph::ASTNode>(one));
                    startState->addVer(vs.first,NfaEdge());
                    vs.second->addVer(endState,NfaEdge());
                    vs.second->setIsAc(false);
                }

                break;
            case NodeType::AND:
                for(auto& one : root->getChilds()){
                    vs = this->regexAST2nfaGraphDfs(dynamic_pointer_cast<NfaGraph::ASTNode>(one));
                    if(!endState){
                        startState = vs.first;
                        endState = vs.second;
                    }else {
                        endState->setIsAc(false);
                        endState->addVer(vs.first,NfaEdge());
                        endState = vs.second;
                    }
                }
                break;
            case NodeType::CHARSET:
                startState = make_shared<NfaNode>();
                endState = make_shared<NfaNode>(true);
                startState->addVer(endState,NfaEdge(root));
                break;
        };

//        处理重复情况
        if(root->getMaxTime() == -1){
            endState->addVer(startState,NfaEdge());
            endState->setIsGreedy(root->isGreedy1());
        }else if(root->getMinTime() == 0){
            startState->addVer(endState,NfaEdge());
            startState->setIsGreedy(root->isGreedy1());
        }



        return {startState,endState};

    }

    NfaNode::NfaNodePtr NfaGraph::getStartState() const {
        return startState;
    }

    NfaNode::NfaNodePtr NfaGraph::getEndState() const {
        return endState;
    }

    void NfaGraph::setStartState(NfaGraph::NfaNodePtr startState) {
        NfaGraph::startState = std::move(startState);
    }

    void NfaGraph::setEndState(NfaGraph::NfaNodePtr endState) {
        NfaGraph::endState = std::move(endState);
    }


    void NfaNode::addVer(NfaNode::NfaNodePtr ver,NfaEdge e){
        this->vers[ver].push_back(e);
        this->edgesOrder.push_back(ver);
//        cout<<this->getUid()<<" add "<<ver->getUid()<<endl;
//        if(!e.isFilterNull()){
//            auto tmp = e.getFilter()->getContext();
//            cout<<" from "<<tmp.getFrom()<< " to " << tmp.getTo() << endl;
//        }

    }

    bool NfaNode::isAc1() const {
        return isAc;
    }

    void NfaNode::setIsAc(bool isAc) {
        NfaNode::isAc = isAc;
    }

    unsigned int NfaNode::getUid() const {
        return uid;
    }

    const unordered_map<NfaNode::NfaNodePtr, vector<NfaEdge>> &NfaNode::getVers() const {
        return vers;
    }

    const vector<NfaNode::NfaNodePtr> &NfaNode::getEdgesOrder() const {
        return edgesOrder;
    }

    bool NfaNode::isGreedy1() const {
        return isGreedy;
    }

    void NfaNode::setIsGreedy(bool isGreedy) {
        NfaNode::isGreedy = isGreedy;
    }


    bool NfaEdge::isFilterNull(){
        return this->isEPSILON();
    }

    bool NfaEdge::match(char c) {
        auto node = this->getFilter();
        auto charSet = node->getContext();
        bool res = false;

        if(charSet.getFrom()<=c && charSet.getTo()>=c) {
            res = true;
        }
//        cout<<"NfaEdge::match:"<<c<<" "<<(charSet.getFrom()<=c && charSet.getTo()>=c)<<" isOpposite1 : "<<charSet.isOpposite1()<<" res :"<<(charSet.isOpposite1() ? !res : res) <<endl;
        return charSet.isOpposite1() ? !res : res;// oppo为1，res取反，为0不变
    }

    NfaEdge::ASTNodePtr NfaEdge::getFilter() const {
        return filter;
    }

    bool NfaEdge::isEPSILON() {
        return this->filter.get() == nullptr;
    }

}